#define _CRT_SECURE_NO_WARNINGS
#include<vector>
#include<cassert>
#include <iostream>
using std::vector;
using std::cout;
using std::endl;
namespace MyMemoryPool
{
	//内存池原理：将大块内存切分为小块内存
	//[大内存]->切分->[小内存1][小内存2]...[小内存n]
	//对于单个大块内存称之为页

	//内存对齐的代码
	//向上对其
	//n为要对齐的字节大小，align是对齐的指针的大小
	//align必须为2的幂
	constexpr inline size_t align_up(size_t n, size_t align)
	{
		return (n + (align - 1)) & ~(align - 1);
	}
	class FixedSizePool
	{
	public:
		//explicit 的主要作用是防止编译器进行不希望的隐式类型转换，增强代码的类型安全性和可读性。
		//默认一页为1024个小块
		explicit FixedSizePool(size_t blockSize, size_t blockPerPage = 1024)
		{

			block_Size = blockSize;
			//这里我们要反町申请的内存是否满足一个指针的大小，否则会出错
			block_Per_Page = adjust_block_size(blockPerPage);
			free_list = nullptr;
		}
		~FixedSizePool()
		{
			for (void* page : Pages)
			{
				//为了避免析构的是一个对象，我们需要使用一个全局的delete来析构内存
				//使用operator delete来释放内存
				::operator delete[](page);
			}
		}
		//分配一小块内存给调用者
		void* allocate()
		{//判断链表是否为空
			if (!free_list)
			{
				//如果为空，则需要向OS申请一页内存并切分为小内存
				expand();
			}
			Node* head = free_list;
			free_list = head->next;
			return head;
		}
		//回收小内存
		void deallocate(void* p)
		{
			if (!p) return;
			//类型强制转换，保证类型安全
			Node* node = static_cast<Node*>(p);
			node->next = free_list;
			free_list = node;
		}
		//访问内存池大小信息
		size_t Get_block_Size() const
		{
			return block_Size;
		}
		size_t Get_block_Per_Page() const
		{
			return block_Per_Page;
		}
		// 统计信息
		void print_stats() const
		{
			std::cout << "内存池统计:" << std::endl;
			std::cout << "  总分配次数: " << total_allocations << std::endl;
			std::cout << "  总释放次数: " << total_deallocations << std::endl;
			std::cout << "  当前使用中: " << (total_allocations - total_deallocations) << std::endl;
			std::cout << "  页数量: " << page_count << std::endl;
			std::cout << "  内存使用量: " << (page_count * block_Size * block_Per_Page) << " 字节" << std::endl;
		}
	private:
		//每次向OS申请一页的内存并切分为很多小内存，将其挂到空闲链表
		void expand()
		{
			//申请一整页内存的大小
			size_t Page_Bite_Size = block_Size * block_Per_Page;
			//向OS申请一页内存
			//为了防止拷贝构造用operator new[]来申请内存
			char* page = static_cast<char*>(::operator new[](Page_Bite_Size));
			Pages.push_back(page);
			//拆分为block_Per_Page个小块内存，构造为free_list链表
			for (size_t i = 0; i < block_Per_Page; ++i)
			{
				char* block = page + i * block_Size;
				Node* n = reinterpret_cast<Node*>(block);
				n->next = free_list;
				free_list = n;
			}


		}
		//要保证申请的内存至少满足一个指针的大小
		size_t adjust_block_size(size_t s)
		{
			size_t min_size = sizeof(void*);
			//alignof函数是获取指针应该对齐的值
			return align_up(s <min_size ? min_size : s, alignof(void*));
			
		}
		//链表结点
		struct Node
		{
			Node* next;
		};
		Node* free_list;//空闲小块的单向链表头
		size_t block_Size; //每个小内存的大小
		size_t block_Per_Page;//每个页的小内存数量
		vector<void*>Pages;//所有已经分配的页。最后统一析构
		// 统计变量
		size_t total_allocations;
		size_t total_deallocations;
		size_t page_count;
	};
}
